from django.utils.translation import ugettext_lazy as _
from django.db.models import fields, get_model
from django.http import HttpResponse, Http404
from django.template import loader, Context

from urllib import urlencode
import simplejson
import libxml2

from results import ResultList
from parser import parse_description

__all__ = ["description", "results_html", "results_json", "results_kml"]

##
## utility functions
##
def get_model_or_404(app_label, model_name):
	model = get_model(app_label, model_name)
	if not model:
		raise Http404("No such model")
	if not hasattr(model._meta, "search") or not model._meta.search:
		raise Http404("No search")
	return model

def get_display_labels(model):
	for field_name in model._meta.search.display_fields:
		try:
			field = model._meta.get_field_by_name(field_name)[0]
			yield field.verbose_name
			continue
		except fields.FieldDoesNotExist:
			pass
		if hasattr(model, field_name):
			field = getattr(model, field_name)
			if hasattr(field, "short_description"):
				yield field.short_description
				continue
		yield field_name

def get_display_fields(obj):
	for field_name in obj._meta.search.display_fields:
		value = getattr(obj, field_name)
		if callable(value):
			value = value()
		if hasattr(value, "render"):
			value = value.render()
		yield field_name, value

##
## views
##
def description(request, app_label, model_name):
	model = get_model_or_404(app_label, model_name)

	response = HttpResponse()
	response["Content-Type"] = "application/opensearchdescription+xml"
	response["Content-Disposition"] = \
	    "attachment; filename=%s_%s_osd.xml" % (app_label, model_name)
	response.write(model._meta.search.description)

	return response

def description_json(request, app_label, model_name):
	model = get_model_or_404(app_label, model_name)

	response = HttpResponse()
	response["Content-Type"] = "text/javascript"
	descr = parse_description(model._meta.search.description)
	response.write(simplejson.dumps(descr))

	return response
	
	
def results_html(request, app_label, model_name,
		 template = "opensearch/results.html"):
	model = get_model_or_404(app_label, model_name)
	r = ResultList(request, model)
	t = loader.get_template(template)

	query = request.GET.copy()
	if "page" in query:
		del query["page"]
		
	c = Context({ "query" : urlencode(query),
		      "page" : r.results() })
	
	response = HttpResponse(t.render(c))
	return response

def results_json(request, app_label, model_name):
	model = get_model_or_404(app_label, model_name)
	
	results = ResultList(request, model).results()

	labels = get_display_labels(model)
	json = {
		"metaData": { "totalProperty": 'results',
			      "root": 'rows',
			      "id": 'id' },
		"results": results.paginator.count,
		"rows": []
		}
	for obj in results.object_list:
		row = map(lambda x: (x[0], unicode(x[1])), get_display_fields(obj))
		row.insert(0, ("fid", obj.pk))
		json["rows"].append(dict(row))
		if not json["metaData"].get("fields"):
			fields = map(lambda x: { "name" : x[0] }, row)
			json["metaData"]["fields"] = fields
	response = HttpResponse()
	response.write(simplejson.dumps(json))
	return response

def results_kml(request, app_label, model_name):
	model = get_model_or_404(app_label, model_name)
	doc = libxml2.newDoc("1.0")
	kml = doc.newChild(None, "kml", None)
	kmlns = kml.newNs("http://earth.google.com/kml/2.0", None)
	kml.setNs(kmlns)
	root = kml.newChild(kmlns, "Document", None)
	
	results = ResultList(request, model).results()
	labels = get_display_labels(model)
	for obj in results.object_list:
		mark = root.newChild(kmlns, "Placemark", None)
		#mark.setProp("id", "%s_%s_%s" % (obj._meta.app_label,
		#				 obj._meta.module_name,
		#				 obj.pk))
		mark.setProp("id", "%s" % obj.pk)
		mark.newChild(kmlns, "name", unicode(obj))
		description = []
		values = map(lambda x: x[1], get_display_fields(obj))
		for label, value in zip(labels, values):
			s = """<b>%s</b>: %s""" % (unicode(label), unicode(value))
			description.append(s)
		description = libxml2.newText("<br/>".join(description))
		dnode = mark.newChild(kmlns, "description", None)
		dnode.addChild(description)

		if model._meta.search.geometry_field:
			geom = getattr(obj, model._meta.search.geometry_field)
			if geom:
				kgeomdoc = libxml2.parseDoc(geom.kml)
				kgeom = kgeomdoc.children
				kgeom.unlinkNode()
				kgeomdoc.freeDoc()
				mark.addChild(kgeom)
			
	response = HttpResponse()
	response["Content-Type"] = "text/plain"
	response.write(doc.serialize("utf-8", True))
	doc.freeDoc()

	return response
	
